#! /bin/bash

#############################################################################################
#                                                                                           #
#   Compiles Faust programs to Android, OSX, iOS, Microsoft 32bits and 64 bits libraries    #
#   suitable for the Unity environment                                                      #
#                                                                                           #
#   (c) Grame, 2017                                                                         #
#                                                                                           #
#############################################################################################

#   The libraries are first wrapped by the unityplugin.cpp architecture file.
#   They have to be used in the Unity environment.
#   The libraries do not work by themselves.
#   They need the FaustPlugin_<dspname>.cs and FaustUtilities_<dspname>.cs files to be functional.
#   These files are automatically generated in this script.
#   By default, all generated files are packed in a unitypackage archive to be read as a package by Unity.
#   Several options are available, see architecture/unity/README.md for more info.

. faustpath
. usage.sh

echoHelp()
{
    usage faust2unity "[options] [Faust options] <file.dsp>"
    platform Android, Linux, MacOSX, iOS, Windows
    require Unity
    echo "Generates a unity package (compressed .unitypackage folder) with all available architecture libraries for faust unity plugin and the C# files required. Use arguments to generate specific architectures (see https://github.com/grame-cncm/faust/tree/master-dev/architecture/unity)"
    option
    option -w32 "generates a Windows 32 bits library"
    option -w64 "generates a Windows 64 bits library"
    option -osx "generates a macOS library"
    option -ios "generates an iOS library"
    option -android "generates Android libraries (armeabi-v7a and x86)."
    option -linux "generates a Linux library"
    option "-nvoices <num>"
    option -source "generates the source files (uncompressed folder)"
    option -universal "generates a universal (arm/intel) external on OSX"
    option -unpacked "generates an unpacked folder with files organized like the Unity Asset hierarchy. Use this options to add specific files in the unity package (in the Assets folder, then use 'encoderunitypackage <folder>' to compress and pack it."
    option "Faust options"
     $ARCH
    echo "See architecture/unity/README.md for more info."
    exit
}

if [ "$#" -eq 0 ]; then
    echo 'Please, provide a Faust file to process !'
    echo ''
    echoHelp
fi

#-----------------------------------------------------------------
# Dispatch command arguments

ALL="1"
W32="0"
W64="0"
OSX="0"
IOS="0"
ANDROID="0"
LINUX="0"
SRC="0"
UNPCK="0"
NVOICES=-1
FAUST_UTILITY=FaustUtilities_template.cs
ARCH=""

while [ $1 ]
do
    p=$1

    if [ $p = "-help" ] || [ $p = "-h" ]; then
        echoHelp
    elif [ $p = "-w32" ]; then
        W32="1"
        ALL="0"
    elif [ $p = "-w64" ]; then
        W64="1"
        ALL="0"
    elif [ $p = "-osx" ]; then
        OSX="1"
        ALL="0"
    elif [ $p = "-ios" ]; then
        IOS="1"
        ALL="0"
    elif [ $p = "-android" ]; then
        ANDROID="1"
        ALL="0"
    elif [ $p = "-linux" ]; then
        LINUX="1"
        ALL="0"
    elif [ $p = "-universal" ]; then
        ARCH="-universal"
    elif [ $p = "-nvoices" ]; then
        shift
        NVOICES=$1
        FAUST_UTILITY=FaustPolyUtilities_template.cs
    elif [ $p = "-source" ]; then
        SRC="1"
        ALL="0"
    elif [ $p = "-unpacked" ]; then
        UNPCK="1"
    elif [ ${p:0:1} = "-" ]; then
        OPTIONS="$OPTIONS $p"
    elif [[ -f "$p" ]] && [ ${p: -4} == ".dsp" ]; then
        FILES="$FILES $p"
    else
        OPTIONS="$OPTIONS $p"
    fi

shift
done

#-------------------------------------
# Compiles all *.dsp files

ARCHIVES=""

for p in $FILES; do

    CUR=$(pwd)
    f=$(basename "$p")
    SRCDIR=$(dirname "$p")
    NAME=${f%.dsp}
    FNAME=FaustPlugin_$NAME
    FIN=$SRCDIR/$FNAME

    # creates final dir / overwrites it if already created
    if [ -d "$FIN" ]; then
        rm -rf "$FIN"
    fi
    mkdir "$FIN"

    # adds README to final dir while setting dspname
    sed "s/<dspname>/$NAME/g" $FAUSTARCH/unity/README.md > $FIN/README.md

    # finds number of parameters, required for the c# scripts
    faust -uim $f -o $NAME.cpp
    grep FAUST_ACTIVES $NAME.cpp > params.txt
    var1=$(cut -d" " -f3- params.txt)
    grep FAUST_PASSIVES $NAME.cpp > params.txt
    var2=$(cut -d" " -f3- params.txt)
    let "var=var1+var2"
    rm $NAME.cpp
    rm params.txt

    # compiles faust to c++ and json (adds JSON to C# string)
    faust -uim -json "$SRCDIR/$f" -o /dev/null;
    tr -d '\n' < $f.json > $NAME.json
    sed 's/\"/\\\\"/g;s/\//\\\//g' $NAME.json > $f.json
    JSON=$(<$f.json)

    # generates c# files
    sed -e "s/MODEL/$NAME/g;s/PLUGNAME/lib$FNAME/g;s/PLUGINNAME/$FNAME/g;s/RELEVANTJSONFILE/$JSON/g;" $FAUSTARCH/unity/$FAUST_UTILITY > $FIN/FaustUtilities_$NAME.cs
    sed -e "s/MODEL/$NAME/g;s/VARIABLES/$var/g;" $FAUSTARCH/unity/FaustPlugin_template.cs > $FIN/$FNAME.cs

    rm -rf $NAME.json
    rm -rf $f.json

    # compiles c++ to binaries

    # w64
    if [ $W64 = "1" ] || [ $ALL = "1" ]; then
        WINBITS="$WINBITS -64"
    fi

    # w32
    if [ $W32 = "1" ] || [ $ALL = "1" ]; then
        WINBITS="$WINBITS -32"
    fi

    # win
    if [ -n "$WINBITS" ]; then
        faust2winunity -nvoices $NVOICES $WINBITS $f || exit
    fi

    # macos
    if [ $OSX = "1" ] || [ $ALL = "1" ]; then
        faust2osxiosunity $ARCH -nvoices $NVOICES $f || exit
    fi

    # ios
    if [ $IOS = "1" ] || [ $ALL = "1" ]; then
        faust2osxiosunity -nvoices $NVOICES -ios $f || exit
    fi

    # android
    if [ $ANDROID = "1" ] || [ $ALL = "1" ]; then
        faust2androidunity -nvoices $NVOICES $f || exit
    fi

    # Linux
    if [ $LINUX = "1" ] || [ $ALL = "1" ]; then
        faust2linuxunity -nvoices $NVOICES $f || exit
    fi

    # Dispatch files in Unity hierarchy
    if [ "$SRC" = "0" ]; then
        if [ "$UNPCK" = "1" ]; then # Specific folder name if unpacked
            PLGN=$FNAME\_Assets/Plugins
            SCRPT=$FNAME\_Assets/Scripts
        else
            PLGN=Assets/Plugins
            SCRPT=Assets/Scripts
        fi

        if [ ! -d "$PLGN" ]; then
            mkdir -p $PLGN
        else
            rm -rf $PLGN
            mkdir -p $PLGN
        fi

        if [ ! -d "$SCRPT" ]; then
            mkdir -p $SCRPT
        else
            rm -rf $SCRPT
            mkdir -p $SCRPT
        fi

        echo $NAME > .VAR
        mv $FNAME/*.cs $SCRPT
        mv $FNAME $PLGN

        if [ "$UNPCK" = "0" ]; then
            encoderunitypackage Assets # encode unity package
            ARCHIVES="$ARCHIVES$FNAME.unitypackage;" # add package name ARCHIVES variable to display compile package name
        elif [ "$UNPCK" = "1" ]; then
            ARCHIVES=$ARCHIVES$FNAME\_Assets\; # add package name ARCHIVES variable to display compile folder
        fi

    elif [ "$SRC" = "1" ]; then
        # add .dsp and .cpp files to sources folder
        faust -uim -i -a $FAUSTARCH/unity/unityplugin.cpp $f -o $NAME.cpp
        mv "$NAME.cpp" "$FNAME/$NAME.cpp"
        cp "$f" "$FNAME/$f"
        SNAME=$FNAME\_sources
        mv "$FNAME" "$SNAME"
        ARCHIVES="$ARCHIVES$SNAME;"
    fi

done

echo "$ARCHIVES"
